package com.example.examsystem.service;

import com.example.examsystem.dto.MenuTreeDto;
import com.example.examsystem.dto.PermissionDto;
import com.example.examsystem.dto.PermissionTreeDto;
import com.example.examsystem.model.Permission;
import com.example.examsystem.model.User;
import com.example.examsystem.repository.PermissionRepository;
import com.example.examsystem.repository.RolePermissionRepository;
import com.example.examsystem.repository.UserRepository;
import com.example.examsystem.repository.UserRoleRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PermissionService {

    private final PermissionRepository permissionRepository;
    private final UserRepository userRepository;
    private final UserRoleRepository userRoleRepository;
    private final RolePermissionRepository rolePermissionRepository;

    /**
     * 获取当前用户的菜单树
     */
    public List<MenuTreeDto> getUserMenuTree() {
        // 获取当前用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            log.warn("用户未认证，返回空菜单");
            return Collections.emptyList();
        }
        
        String username = authentication.getName();
        log.info("获取用户 {} 的菜单树", username);
        
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在: " + username));
        
        // 检查是否为管理员
        boolean isAdmin = user.getRoles().stream()
            .anyMatch(role -> "ADMIN".equals(role.getName()));
        
        log.info("用户 {} 是否为管理员: {}", username, isAdmin);
        
        Set<Permission> permissions;
        if (isAdmin) {
            // 管理员获取所有菜单权限
            permissions = new HashSet<>(permissionRepository.findByTypeAndVisible(Permission.PermissionType.MENU, true));
            log.info("管理员获取到 {} 个菜单权限", permissions.size());
        } else {
            // 普通用户获取角色菜单权限
            permissions = getUserPermissions(user.getId()).stream()
                .filter(p -> Permission.PermissionType.MENU.equals(p.getType()) && p.getVisible())
                .collect(Collectors.toSet());
            log.info("普通用户获取到 {} 个菜单权限", permissions.size());
        }
        
        // 构建菜单树
        List<MenuTreeDto> menuTree = buildMenuTree(new ArrayList<>(permissions));
        log.info("构建菜单树完成，返回 {} 个根菜单", menuTree.size());
        
        return menuTree;
    }

    /**
     * 构建菜单树
     */
    private List<MenuTreeDto> buildMenuTree(List<Permission> permissions) {
        Map<Long, MenuTreeDto> menuMap = permissions.stream()
            .collect(Collectors.toMap(
                Permission::getId,
                this::convertToMenuTreeDto
            ));
        
        List<MenuTreeDto> rootMenus = new ArrayList<>();
        
        for (MenuTreeDto menu : menuMap.values()) {
            if (menu.getParentId() == null) {
                rootMenus.add(menu);
            } else {
                MenuTreeDto parent = menuMap.get(menu.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(menu);
                }
            }
        }
        
        // 排序
        sortMenuTree(rootMenus);
        return rootMenus;
    }

    /**
     * 菜单树排序
     */
    private void sortMenuTree(List<MenuTreeDto> menus) {
        if (menus == null || menus.isEmpty()) {
            return;
        }
        
        menus.sort(Comparator.comparing(MenuTreeDto::getSort));
        
        for (MenuTreeDto menu : menus) {
            if (menu.getChildren() != null) {
                sortMenuTree(menu.getChildren());
            }
        }
    }

    /**
     * 转换为菜单树DTO
     */
    private MenuTreeDto convertToMenuTreeDto(Permission permission) {
        MenuTreeDto dto = new MenuTreeDto();
        dto.setId(permission.getId());
        dto.setName(permission.getName());
        dto.setPath(permission.getPath());
        dto.setComponent(permission.getComponent());
        dto.setIcon(permission.getIcon());
        dto.setSort(permission.getSort());
        dto.setParentId(permission.getParentId());
        dto.setType(permission.getType().name());
        dto.setVisible(permission.getVisible());
        return dto;
    }

    /**
     * 获取当前用户的权限列表（字符串格式）
     */
    public List<String> getUserPermissions() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return Collections.emptyList();
        }
        
        String username = authentication.getName();
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        boolean isAdmin = user.getRoles().stream()
            .anyMatch(role -> "ADMIN".equals(role.getName()));
        
        Set<Permission> permissions;
        if (isAdmin) {
            permissions = new HashSet<>(permissionRepository.findAll());
        } else {
            permissions = getUserPermissions(user.getId());
        }
        
        return permissions.stream()
            .map(permission -> permission.getResource() + ":" + permission.getAction())
            .collect(Collectors.toList());
    }

    /**
     * 检查用户是否有指定权限
     */
    public boolean hasPermission(String permission) {
        List<String> userPermissions = getUserPermissions();
        return userPermissions.contains(permission);
    }

    /**
     * 获取用户权限集合
     */
    private Set<Permission> getUserPermissions(Long userId) {
        List<Long> roleIds = userRoleRepository.findRoleIdsByUserId(userId);
        if (roleIds.isEmpty()) {
            return new HashSet<>();
        }
        
        List<Long> permissionIds = rolePermissionRepository.findPermissionIdsByRoleIds(roleIds);
        if (permissionIds.isEmpty()) {
            return new HashSet<>();
        }
        
        return new HashSet<>(permissionRepository.findAllById(permissionIds));
    }

    /**
     * 获取所有权限树
     */
    public List<PermissionTreeDto> getAllPermissionTree() {
        List<Permission> allPermissions = permissionRepository.findAllByOrderBySort();
        return buildPermissionTree(allPermissions);
    }

    /**
     * 构建权限树
     */
    private List<PermissionTreeDto> buildPermissionTree(List<Permission> permissions) {
        Map<Long, PermissionTreeDto> permissionMap = permissions.stream()
            .collect(Collectors.toMap(
                Permission::getId,
                this::convertToPermissionTreeDto
            ));
        
        List<PermissionTreeDto> rootPermissions = new ArrayList<>();
        
        for (PermissionTreeDto dto : permissionMap.values()) {
            if (dto.getParentId() == null) {
                rootPermissions.add(dto);
            } else {
                PermissionTreeDto parent = permissionMap.get(dto.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(dto);
                }
            }
        }
        
        sortPermissionTree(rootPermissions);
        return rootPermissions;
    }

    private void sortPermissionTree(List<PermissionTreeDto> permissions) {
        if (permissions == null || permissions.isEmpty()) {
            return;
        }
        
        permissions.sort(Comparator.comparing(PermissionTreeDto::getSort));
        
        for (PermissionTreeDto permission : permissions) {
            if (permission.getChildren() != null) {
                sortPermissionTree(permission.getChildren());
            }
        }
    }

    private PermissionTreeDto convertToPermissionTreeDto(Permission permission) {
        PermissionTreeDto dto = new PermissionTreeDto();
        dto.setId(permission.getId());
        dto.setName(permission.getName());
        dto.setResource(permission.getResource());
        dto.setAction(permission.getAction());
        dto.setDescription(permission.getDescription());
        dto.setType(permission.getType().name());
        dto.setPath(permission.getPath());
        dto.setComponent(permission.getComponent());
        dto.setIcon(permission.getIcon());
        dto.setSort(permission.getSort());
        dto.setVisible(permission.getVisible());
        dto.setParentId(permission.getParentId());
        dto.setCreatedAt(permission.getCreatedAt());
        dto.setUpdatedAt(permission.getUpdatedAt());
        return dto;
    }

    public List<PermissionDto> getAllPermissions() {
        List<Permission> permissions = permissionRepository.findAllByOrderBySort();
        return permissions.stream()
            .map(this::convertToPermissionDto)
            .collect(Collectors.toList());
    }

    public PermissionDto createPermission(PermissionDto permissionDto) {
        Permission permission = new Permission();
        permission.setName(permissionDto.getName());
        permission.setResource(permissionDto.getResource());
        permission.setAction(permissionDto.getAction());
        permission.setDescription(permissionDto.getDescription());
        permission.setType(Permission.PermissionType.valueOf(permissionDto.getType()));
        permission.setPath(permissionDto.getPath());
        permission.setComponent(permissionDto.getComponent());
        permission.setIcon(permissionDto.getIcon());
        permission.setSort(permissionDto.getSort());
        permission.setVisible(permissionDto.getVisible());
        permission.setParentId(permissionDto.getParentId());
        
        Permission savedPermission = permissionRepository.save(permission);
        return convertToPermissionDto(savedPermission);
    }

    public PermissionDto updatePermission(Long id, PermissionDto permissionDto) {
        Permission permission = permissionRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("权限不存在"));
        
        permission.setName(permissionDto.getName());
        permission.setResource(permissionDto.getResource());
        permission.setAction(permissionDto.getAction());
        permission.setDescription(permissionDto.getDescription());
        permission.setType(Permission.PermissionType.valueOf(permissionDto.getType()));
        permission.setPath(permissionDto.getPath());
        permission.setComponent(permissionDto.getComponent());
        permission.setIcon(permissionDto.getIcon());
        permission.setSort(permissionDto.getSort());
        permission.setVisible(permissionDto.getVisible());
        permission.setParentId(permissionDto.getParentId());
        
        Permission savedPermission = permissionRepository.save(permission);
        return convertToPermissionDto(savedPermission);
    }

    public void deletePermission(Long id) {
        Permission permission = permissionRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("权限不存在"));
        
        List<Permission> children = permissionRepository.findByParentId(id);
        if (!children.isEmpty()) {
            throw new RuntimeException("存在子权限，无法删除");
        }
        
        List<Long> roleIds = rolePermissionRepository.findRoleIdsByPermissionId(id);
        if (!roleIds.isEmpty()) {
            throw new RuntimeException("权限正在被角色使用，无法删除");
        }
        
        permissionRepository.delete(permission);
    }

    public PermissionDto getPermissionById(Long id) {
        Permission permission = permissionRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("权限不存在"));
        return convertToPermissionDto(permission);
    }

    public List<PermissionDto> getPermissionsByType(String type) {
        Permission.PermissionType permissionType = Permission.PermissionType.valueOf(type);
        List<Permission> permissions = permissionRepository.findByType(permissionType);
        return permissions.stream()
            .map(this::convertToPermissionDto)
            .collect(Collectors.toList());
    }

    public List<PermissionDto> getChildPermissions(Long parentId) {
        List<Permission> permissions = permissionRepository.findByParentId(parentId);
        return permissions.stream()
            .map(this::convertToPermissionDto)
            .collect(Collectors.toList());
    }

    public boolean existsByName(String name, Long excludeId) {
        Optional<Permission> permission = permissionRepository.findByName(name);
        if (permission.isEmpty()) {
            return false;
        }
        
        if (excludeId != null && permission.get().getId().equals(excludeId)) {
            return false;
        }
        
        return true;
    }

    private PermissionDto convertToPermissionDto(Permission permission) {
        PermissionDto dto = new PermissionDto();
        dto.setId(permission.getId());
        dto.setName(permission.getName());
        dto.setResource(permission.getResource());
        dto.setAction(permission.getAction());
        dto.setDescription(permission.getDescription());
        dto.setType(permission.getType().name());
        dto.setPath(permission.getPath());
        dto.setComponent(permission.getComponent());
        dto.setIcon(permission.getIcon());
        dto.setSort(permission.getSort());
        dto.setVisible(permission.getVisible());
        dto.setParentId(permission.getParentId());
        dto.setCreatedAt(permission.getCreatedAt());
        dto.setUpdatedAt(permission.getUpdatedAt());
        return dto;
    }
}





